package request

import (
	"context"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/buffer"
	"git.gz.internal.jumaiyx.cn/pkg/tnet/pack"
	"github.com/panjf2000/gnet/v2"
	"google.golang.org/protobuf/proto"

	"time"
)

type IRequest interface {
	// GetConnection 获取链接
	GetConnection() gnet.Conn
	GetMessage() pack.IMessage
	// GetData 获取信息体
	GetData() []byte
	// GetMsgID 获取协议号
	GetMsgID() uint32
	// GetMsgLen 获取信息长度
	GetMsgLen() int
	// GetUserId 获取用户id，只支持UDP
	GetUserId() int64
	// Context 获取上下文
	Context() context.Context
	// ConnId 获取连接id
	ConnId() int

	// AsyncWrite 信息发送
	AsyncWrite(msgId uint32, message proto.Message, callback gnet.AsyncCallback) error

	// Send 信息发送
	Send(msgId uint32, message proto.Message) error
}

// Request 请求
type Request struct {
	conn    gnet.Conn     // the connection which has been established with the client(已经和客户端建立好的链接)
	message pack.IMessage // the request data sent by the client(客户端请求的数据)
	context context.Context
}

func NewRequest(conn gnet.Conn, message pack.IMessage) (IRequest, func()) {
	ctx := context.Background()
	ctx, cancelFunc := context.WithTimeout(ctx, time.Second*20)
	return &Request{
			conn:    conn,
			message: message,
			context: ctx,
		}, func() {
			cancelFunc()
		}
}

func (r *Request) GetConnection() gnet.Conn {
	return r.conn
}

func (r *Request) GetMessage() pack.IMessage {
	return r.message
}

func (r *Request) GetData() []byte {
	return r.message.GetData()
}

func (r *Request) GetMsgID() uint32 {
	return r.message.GetMsgId()
}

func (r *Request) GetMsgLen() int {
	return r.message.GetLen()
}

func (r *Request) GetUserId() int64 {
	return int64(r.message.GetUserId())
}

func (r *Request) Context() context.Context {
	return r.context
}

func (r *Request) ConnId() int {
	return r.conn.Fd()
}

func (r *Request) Send(msgId uint32, message proto.Message) error {
	var (
		byt []byte
		err error
	)
	if message != nil {
		byt, err = Marshal(message)
		if err != nil {
			return err
		}
	}
	bytes, _ := buffer.New(msgId, byt)
	_, err = r.conn.Write(bytes)
	return err
}

func (r *Request) AsyncWrite(msgId uint32, message proto.Message, callback gnet.AsyncCallback) error {
	var (
		byt []byte
		err error
	)
	if message != nil {
		byt, err = Marshal(message)
		if err != nil {
			return err
		}
	}
	bytes, _ := buffer.New(msgId, byt)
	_, err = r.conn.Write(bytes)
	return r.conn.AsyncWrite(bytes, callback)
}
